﻿using codeparser.net.v2.Aspects;
using codeparser.net.v2.ConfigurationItems;
using codeparser.net.v2.ContentTransformer;
using codeparser.net.v2.Contracts;
using codeparser.net.v2.Entities;
using codeparser.net.v2.Exceptions;

using configuration.net;

using System;
using System.Collections.Generic;
using System.Linq.Dynamic;
using System.Linq.Expressions;
using System.Xml;
using System.Xml.XPath;

namespace codeparser.net.v2
{
    /// <summary>
    /// Represents a tag configuration.
    /// </summary>
    public class TagConfiguration : IXmlWriter
    {
        /// <summary>
        /// Initializes a new instance of the TagConfiguration type.
        /// </summary>
        [LoggingAspect]
        public TagConfiguration()
        {
            // Initialize the fields.
            this._tags = new Dictionary<string, Tag>();
            this.ContentTransformer = new Transformer();
        }

        /// <summary>
        /// Contains the tags.
        /// </summary>
        private Dictionary<string, Tag> _tags;

        /// <summary>
        /// Gets the tags.
        /// </summary>
        /// <value>The tags.</value>
        public Dictionary<string, Tag> Tags
        {
            get
            {
                return this._tags;
            }
        }

        /// <summary>
        /// Gets or sets the content transformer.
        /// </summary>
        /// <value>The content transformer.</value>
        public Transformer ContentTransformer
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the tag for the specified tag element name.
        /// </summary>
        /// <param name="name">The name of the element.</param>
        /// <returns>The tag.</returns>
        public Tag this[string name]
        {
            get
            {
                if (!this.Tags.ContainsKey(name))
                {
                    return null;
                }

                return this.Tags[name];
            }
        }

        /// <summary>
        /// Adds the specified tag to the tag configuration.
        /// </summary>
        /// <param name="tag">The tag.</param>
        [LoggingAspect]
        public void Add(Tag tag)
        {
            this.Tags.Add(tag.Element.Name, tag);
        }

        /// <summary>
        /// Loads the tag configuration from the specified XML reader.
        /// </summary>
        /// <param name="document">The XML document.</param>
        /// <returns>The loaded tag configuration.</returns>
        [LoggingAspect]
        internal static TagConfiguration Load(XmlDocument document)
        {
            // Create the tag configuration.
            TagConfiguration tagConfiguration = new TagConfiguration();

            // Get the configuration.
            Configuration configuration = new Configuration(document);
            ConfigurationElement tags = configuration.Required<CodeparserNet>().Required<TagConfiguration>().Optional<Tags>();
            ConfigurationElement transformers = configuration.Required<CodeparserNet>().Required<TagConfiguration>().Optional<ContentTransformers>();

            // Get the tag configuration.
            if (tags != null)
            {
                foreach (var tagNode in tags.List<Tag>())
                {
                }
            }

            // Get the transformer configuration.
            if (transformers != null)
            {
                Transformer currentTransformer = tagConfiguration.ContentTransformer;
                foreach (var transformerNode in transformers.List<Transformer>())
                {
                    // Get the lambda expression.
                    string func = transformerNode.Value<TransformFunc>().AsString();
                    func = func.Substring(func.IndexOf("=>") + 2).Trim();
                    Expression<Func<string, string>> transformFunc =
                        DynamicExpression.ParseLambda<string, string>(func);

                    // Get the scope.
                    TransformerScope scope = (TransformerScope)Enum.Parse(typeof(TransformerScope), transformerNode.Value<Scope>().AsString());

                    // Add the lambda expression to the current transformer.
                    currentTransformer = currentTransformer.Add(transformFunc, scope);
                }
            }

            // Return the tag configuration to the caller.
            return tagConfiguration;
        }

        /// <summary>
        /// Saves the tag configuration to the specified XML writer.
        /// </summary>
        /// <param name="writer">The XML writer.</param>
        [LoggingAspect]
        void IXmlWriter.Save(XmlWriter writer)
        {
            // Write the configuration.
            writer.WriteStartElement("TagConfiguration");
            {
                // Write the tags.
                writer.WriteStartElement("Tags");
                {
                    foreach (Tag tag in this._tags.Values)
                    {
                        ((IXmlWriter)tag).Save(writer);
                    }
                }
                writer.WriteEndElement();

                // Write the content transformers.
                writer.WriteStartElement("ContentTransformers");
                {
                    ((IXmlWriter)this.ContentTransformer).Save(writer);
                }
                writer.WriteEndElement();
            }
            writer.WriteEndElement();
        }
    }
}